import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { message, Upload } from 'antd';
import SparkMD5 from 'spark-md5';
import Button from '../../../../common/Button';
import ButtonArray from '../../../../common/ButtonArray';
import {
  ALL_FILE,
  COMMON_SUCCESS_STATE,
  DIRECTORIES,
  FILES,
  PAUSED_RESOLVE
} from '../../../../../constant';
import 'antd/lib/message/style';
import 'antd/lib/modal/style';
import 'antd/lib/upload/style';
import './index.less';
import { setPartFileUploadAttribute } from '../../../../../redux/actions/fileUploadAttribute';
import { getPage, removePage, setPage } from '../../../../../utils/storageUtils';
import { showTransfer } from '../../../../../redux/actions/transferVisible';
import { all } from '../../../../../api/ajax';
import { deleteFiles, deleteFolders } from '../../../../../api';
import { setFiles } from '../../../../../redux/actions/files';

class ContentTool extends PureComponent {

  static propTypes = {
    category: PropTypes.object,
    folder: PropTypes.object,
    changeCreateFolderStatus: PropTypes.func,
    setPartFileUploadAttribute: PropTypes.func,
    uploadList: PropTypes.object,
    showTransfer: PropTypes.func,
    files: PropTypes.object,
    setFiles: PropTypes.func
  };

  state = {
    fileList: []
  };

  // 新建文件夹
  createFolder = () => {
    const { changeCreateFolderStatus } = this.props;
    changeCreateFolderStatus(true);
  };

  // 删除文件
  deleteFile = async () => {
    const { category } = this.props;
    //  过滤出选中的文件
    let map = this.queryCheckedFiles();
    let requestQueue = [];
    for (const key in map) {
      if (key === DIRECTORIES) {
        requestQueue.push(deleteFolders(map[key]));
      } else if (key === FILES) {
        requestQueue.push(deleteFiles(map[key]));
      }
    }
    // 发送请求删除
    let ary = await all(requestQueue);
    ary.forEach(({ code }) => {
      console.log(code);
      if (code !== COMMON_SUCCESS_STATE) {
        message.error('删除文件失败');
        return false;
      }
    });
    message.success('删除文件成功');
    category.target.click();
  };

  // 重命名当前文件
  renameFile = async () => {
    const {
      files,
      setFiles
    } = this.props;
    let map = this.queryCheckedFiles();
    let keys = Object.keys(map);
    if (keys.length !== 2) {
      message.error('选择文件异常');
      return false;
    }
    let curIndex = map[keys[0]];
    let curKey = keys[1];
    let renameAllFile = map[curKey];
    if (renameAllFile.length !== 1) {
      message.error('选择文件异常');
      return false;
    }
    // 更新重命名状态
    files[curKey][curIndex].rename = true;
    setFiles(files);
  };

  // 查询当前选择的文件夹或者目录
  queryCheckedFiles = () => {
    const { files: allFiles } = this.props;
    //  过滤出选中的文件
    let dirs = allFiles[DIRECTORIES];
    let files = allFiles[FILES];
    let buildDirIds = [];
    let buildFileIds = [];
    // 保存查询到的最后索引
    let folderIndex = -1;
    let fileIndex = -1;
    if (dirs) {
      buildDirIds = dirs.filter((item, index) => {
        if (item.checked) {
          folderIndex = index;
          return item;
        }
      })
        .map((item) => item.id);
    }
    if (files) {
      buildFileIds = files.filter((item, index) => {
        if (item.checked) {
          fileIndex = index;
          return item;
        }
      })
        .map((item) => item.id);
    }
    let result = {};
    if (buildDirIds.length > 0) {
      result.folderIndex = folderIndex;
      result[DIRECTORIES] = buildDirIds;
    }
    if (buildFileIds.length > 0) {
      result.fileIndex = fileIndex;
      result[FILES] = buildFileIds;
    }
    return result;
  };

  // 显示传输列表
  showTransfer = (event) => {
    if (event.file.size <= 0) {
      return false;
    }
    const { showTransfer } = this.props;
    showTransfer();
  };

  render () {
    let {
      folder,
      category,
      setPartFileUploadAttribute,
      files
    } = this.props;
    // 按钮组数据项
    let ary = [
      {
        name: '新建文件夹',
        icon: 'icon-newfolder',
        event: this.createFolder
      },
      {
        name: '新建在线文档',
        icon: 'icon-new-wp',
      },
      {
        name: '离线下载',
        icon: 'icon-download',
      },
    ];
    let ary1 = [
      {
        name: '分享',
        icon: 'icon-share',
      },
      {
        name: '共享',
        icon: 'icon-size-enjoy-together',
        display: files.checkedCount >= 2 ? 'none' : 'block'
      },
      {
        name: '下载',
        icon: 'icon-download',
      },
      {
        name: '删除',
        icon: 'icon-delete',
        event: this.deleteFile
      },
      {
        name: '重命名',
        icon: 'icon-rename',
        event: this.renameFile,
        display: files.checkedCount >= 2 ? 'none' : 'block'
      },
      {
        name: '复制',
        icon: 'icon-copy',
      },
      {
        name: '移动',
        icon: 'icon-move',
      }
    ];
    // 剔除对文件夹的操作，在其他分类下
    if (category.id !== ALL_FILE) {
      ary.shift();
    }
    // 上传按钮基本属性
    const uploadProp = {
      onRemove: (file) => {
        // ...
        console.log(file);
      },
      // 此方法的主要作用，就是对大文件进行拆分，并且构造各种需要的值
      beforeUpload: async (file) => {
        if (file.size <= 0) {
          message.error('不能上传为空的文件');
          return false;
        }
        // 判断预处理是否为空
        // 兼容性处理
        let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
          // 定义切片大小 5M
          chunkSize = 1024 * 1024 * 5,
          // 切片总数量
          chunks = Math.ceil(file.size / chunkSize),
          // 当前上传切片的索引
          currentChunk = 0,
          fileMd5 = '',
          // 对ArrayBuffer进行md5加密，产生一个MD5字符串
          spark = new SparkMD5.ArrayBuffer(),
          // 用于计算每个chunk的md5
          chunkFileReader = new FileReader(),
          // 用于计算总文件的MD5值
          totalFileReader = new FileReader();
        // 将当前文件装换为ArrayBuffer
        totalFileReader.readAsArrayBuffer(file);

        // 初始化状态
        setPartFileUploadAttribute({
          [file.uid]: {
            webkitRelativePath: file.webkitRelativePath, // 目录选择路径，单文件选择为空
            fileName: file.name, // 文件名称
            fileSize: file.size, // 文件大小
            contentType: file.type,
            folder: folder.id || 0,
            uploadRequest: false, // 上传请求
            uploading: false, // 上传中
            uploaded: false // 上传完成
          }
        });

        // 中断解析标记
        setPage(file.uid + PAUSED_RESOLVE, false);

        // 等待md5计算完成
        // 整个文件Blob加载回调
        totalFileReader.onload = (e) => {
          // 对整个file对象生成md5值
          spark.append(e.target.result);
          // 设置MD5值
          fileMd5 = spark.end();
        };

        // 用于上传所有分片的MD5信息
        let params = {
            chunks: [],
            file: {}
          },
          // 用于存储每个chunk每个arrayBuffer对象，用于上传数据
          arrayBufferData = [];

        // chunk分片Blob加载回调
        chunkFileReader.onload = (e) => {
          // 对每个分片进行md5加密
          spark.append(e.target.result);
          // 每一个分片需要设置的必要信息
          let obj = {
            // 总分片个数
            chunks,
            // 位于第几个chunk
            chunk: currentChunk + 1,
            // 计算分片的起始位置，相对于整个文件流来说
            start: currentChunk * chunkSize,
            // 计算分片的结束位置
            end: (((currentChunk + 1) * chunkSize) >= file.size) ? file.size : ((currentChunk + 1) * chunkSize),
            // 当前分片的md5
            chunkMd5: spark.end()
          };
          // 每一次分片onload,currentChunk都需要增加，以便来计算分片的次数
          currentChunk++;
          // 设置分片基本信息
          params.chunks.push(obj);
          // params初始化赋值
          params.file.fileMd5 = fileMd5;
          // 当前文件名称
          params.file.fileName = file.name;
          // 当前文件大小
          params.file.fileSize = file.size;
          // 上传至本地，需要设置本地路径，至FastDFS无需设置
          // uploadParams.localPath = 'D:\\upload'
          // 设置目录层级
          params.file.folderId = folder.id || 0;
          // 将每一块分片的ArrayBuffer存储起来，用来分片上传
          let tmp = {
            chunk: obj.chunk,
            currentBuffer: e.target.result
          };
          arrayBufferData.push(tmp);

          if (currentChunk < chunks) {
            // 当前分片没有达到总数时
            // 判断文件是否继续解析
            if (!getPage(file.uid + PAUSED_RESOLVE)) {
              loadNext();
              // 计算预处理速度
              setPartFileUploadAttribute({
                [file.uid]: {
                  preUploading: true,
                  preUploadPercent: Number(currentChunk / chunks * 100)
                    .toFixed(2)
                }
              });
            } else {
              removePage(file.uid + PAUSED_RESOLVE);
            }
          } else {
            // 到达分片长度
            // 记录所有chunks的长度
            params.file.fileChunks = params.chunks.length;
            // 预处理结束，将要上传的参数，ArrayBuffer的数据将存储起来
            setPartFileUploadAttribute({
              [file.uid]: {
                preUploading: false,
                uploadParams: params,
                arrayBufferData,
                chunkSizes: chunks,
                preUploadPercent: 100
              }
            });
            // 移出解析标记
            removePage(file.uid + PAUSED_RESOLVE);
          }
        };

        // 分片读取失败回调
        chunkFileReader.onerror = () => {
          message.error('\'oops, something went wrong.\'');
        };

        function loadNext () {
          let start = currentChunk * chunkSize,
            end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
          chunkFileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
        }

        // 加载下一块分片
        loadNext();
        return false;
      },
      fileList: this.state.fileList
    };
    return (
      <>
        <div className="pan_content_tool">
          <div className="pan_content_tool_left">
            {
              files.checkedCount === 0
                ? (<><Button style={{ padding: '10px 16px' }} className="iconfont icon-upload"
                  onClick={this.uploadSingle}>
                  上传
                  <ul className="select_upload_type">
                    <li>
                      <Upload
                        {...uploadProp}
                        onChange={this.showTransfer}
                        multiple>
                        上传文件
                      </Upload>
                    </li>
                    <li>
                      <Upload
                        {...uploadProp}
                        onChange={this.showTransfer}
                        directory
                        multiple>
                        上传文件夹
                      </Upload>
                    </li>
                  </ul>
                </Button>
                <ButtonArray data={ary} size="large"/></>)
                : <ButtonArray data={ary1} size="large"/>
            }
          </div>
          <div className="pan_content_tool_right">
            <i className="iconfont icon-search"/>
            <input type="text" name="keyword" placeholder="搜索我的文件"/>
          </div>
        </div>
      </>
    );
  }
}

export default connect(
  (state) => ({
    category: state.category,
    folder: state.folder,
    uploadList: state.fileUploadAttribute,
    files: state.files
  }),
  {
    setPartFileUploadAttribute,
    showTransfer,
    setFiles
  }
)(ContentTool);
